package __MACOSX;

import be.kuleuven.cs.som.annotate.*;

public class IRobot {
	private long energy;
	public IRobot( Long moveenergy,long kwartenergy,Long maxenergy ,Long energie,long[] direction,long[] position,long[] maxposition,long[] minposition) throws outofboardexception{
		this.maxenergie = maxenergy;
		this.maxpositie = maxposition;
		this.minpositie = minposition;
		setenergy(energie);
		setrichting(direction);
		setpositie(position );
		this.kwartdraaienergy = kwartenergy;
		this.moveenergy = moveenergy;

	}
	public IRobot( Long maxenergy ,Long energie,long[] direction,long[] position,long[] maxposition,long[] minposition) throws outofboardexception{
		this((long) 500,100, maxenergy , energie,direction, position, maxposition, minposition);
	}
	public IRobot( Long energie,long[] direction,long[] position,long[] maxposition,long[] minposition) throws outofboardexception{
		this((long) 20000 , energie,direction, position, maxposition, minposition);
	}
	public IRobot( Long energie,long[] direction,long[] position) throws outofboardexception{
		long[] temp={Long.MAX_VALUE,Long.MAX_VALUE};
		long[] temp2={0,0};
		this.maxenergie = 20000;
		this.maxpositie = temp;
		this.minpositie = temp2;
		setenergy(energie);
		setrichting(direction);
		setpositie(position);
		this.kwartdraaienergy =100;
		this.moveenergy = 500;

	}
	public IRobot() throws outofboardexception{
		long[] temp={Long.MAX_VALUE,Long.MAX_VALUE};
		long[] temp2={0,0};
		long[] temp3={0,1};
		setenergy(20000);
		setrichting(temp3);
		setpositie(temp2);
		this.kwartdraaienergy =100;
		this.moveenergy = 500;
		this.maxenergie = 20000;
		this.maxpositie = temp;
		this.minpositie = temp2;
	}
	/**
	 * 
	 * geef de energie van de robot terug
	 * 	
	 */
	@Basic
	public long getenergy(){
		return energy;
	}
	/**
	 * 
	 * @param energie
	 * 		De energie die wordt getest.
	 * @return
	 * 		True als en slechts als de energie groter of gelijk aan 0 is en kleiner of gelijk aan de maximumwaarde
	 * 		|return == ( energie >= 0)  && (energie <= getmaxenergie())
	 * @basic	
	 */
	public boolean isvalidenergy(long energie){
		return energie >= 0  && energie <= getmaxenergie();
	}
	/**
	 * Zet de energie op de gevraagde energie
	 * 
	 * @param energie
	 * De hoeveelheid energie die de robot heeft
	 * 
	 * @pre De gegeven energie voldoet aan de invarianten
	 * 		| isvalidenergy(energie)
	 * 
	 * @post De energiehoeveelheid is gelijk aan de gegeven energie
	 * 		| new.getenergy == energie
	 */
	private void setenergy(long energie){
		assert isvalidenergy(energie);
		energy = energie;
	}
	/**
	 * Verlaag de energie waarde met het gegeven aantal
	 * 
	 * @param energie
	 * 		De energie die wordt afgetrokken van de oorspronkelijke
	 * 
	 * @pre De energie moet aan de voorwaarden van de krachtbron voldoen
	 * 		| isvalidenergy(energie)
	 * @pre De nieuwe energie moet voldoen aan de voorwaarden van de krachtbron
	 * 		| isvalidenergy(getenergy() - energie)
	 * @post De nieuwe energie is de oude energie min de energie die we willen laten verdwijnen
	 * 		| new.getenergy() == getenergy() - energie
	 */
	private void removeenergy(long energie){
		assert isvalidenergy(energie);
		assert isvalidenergy(getenergy() - energie);
		setenergy(getenergy() - energie);
	}
	private final long kwartdraaienergy;
	/**
	 * geef de energie voor een kwartdraai terug
	 * 	
	 */
	@Basic
	public long getkwartenergy(){
		return kwartdraaienergy;
	}
	private final long moveenergy;
	/**
	 * geef de energie voor een voorwaartse beweging terug
	 * 
	 */
	@Basic
	public long getmoveenergy(){
		return moveenergy;
	}
	private final long maxenergie;
	/**
	 * geef de maximum energie van de robot terug
	 * 
	 */
	@Basic
	public long getmaxenergie(){
		return maxenergie;
	}

	private long[] richting;
	/**
	 * 
	 * geef de richting weer 
	 * @note eerste cijfer is x-coordinaat tweede y-coordinaat
	 * 
	 */
	@Basic

	public long[] getrichting(){
		return richting;
	}
	/**
	 * Verander de richting naar de gegeven waarde
	 * 
	 * @param richting
	 * 		De nieuwe richting
	 * 
	 * @pre De richting voldoet aan de voorwaarden
	 * 		|isvalidrichting(richting)
	 * 
	 * @post De nieuwe richting is gelijk aan de gegeven waarde
	 * 		|new.getrichting == richting 
	 * 
	 */
	private void setrichting(long[] richting){
		assert isvalidrichting(richting);
		this.richting = richting;
	}
	/**
	 *test ofdat de richting voldoet aan de notatie 
	 * 
	 * @param richting
	 * 			De richting die wordt getest
	 * @return True als en slechts als 1 van beide waarden 0 is en de andere 1 of -1
	 * 		|result == (richting[0]==0 && richting[1]== 1)
			||(richting[0]==0 && richting[1]== -1)
			||(richting[0]==1 && richting[1]== 0)
			||(richting[0]==-1 && richting[1]== 0);
	 */
	public static boolean isvalidrichting(long[] richting){
		return (richting[0]==0 && richting[1]== 1)
				||(richting[0]==0 && richting[1]== -1)
				||(richting[0]==1 && richting[1]== 0)
				||(richting[0]==-1 && richting[1]== 0);
	}
	/**
	 * de robot maakt een rechtse kwartdraai
	 * @post if (getrichting()=={0,1}) then new.getrichting()=={1,0}
	 * @post if (getrichting()=={0,-1}) then new.getrichting()=={-1,0}
	 * @post if (getrichting()=={1,0}) then new.getrichting()=={0,-1}
	 * @post if (getrichting()=={-1,0}) then new.getrichting()=={0,1}
	 */
	private void kwartdraairechts(){

		long[] temp = {getrichting()[1],-getrichting()[0]};
		setrichting(temp);

	}
	/**
	 * de robot maakt een links kwartdraai
	 * @post if (getrichting()=={0,1}) then new.getrichting()=={-1,0}
	 * @post if (getrichting()=={0,-1}) then new.getrichting()=={1,0}
	 * @post if (getrichting()=={1,0}) then new.getrichting()=={0,1}
	 * @post if (getrichting()=={-1,0}) then new.getrichting()=={0,-1}
	 */
	private void kwartdraailinks(){

		long[] temp = {-getrichting()[1],getrichting()[0]};
		setrichting(temp);

	}
	private long[] positie;
	/**
	 * 
	 * geef de positie weer 
	 * @note eerste cijfer is x-coordinaat tweede y-coordinaat
	 * 
	 */
	@Basic
	public long[] getpositie(){
		return positie;
	}
	/**
	 * vervang de positie door de nieuwe waarde
	 * @param plaats
	 *  		de  waarde voor de nieuwe positie
	 * @throws outofboardexception
	 * 			 de nieuwe locatie bevindt zich niet op het bord
	 * 			|!isvalidpositie(plaats)
	 * @post new.getpositie()==plaats
	 */
	private void setpositie(long [] plaats)throws outofboardexception{
		if (!isvalidpositie(plaats)){
			throw new outofboardexception();
		}
		positie=plaats;
	}
	/**
	 * controleert of de positie voldoet aan de voorwaarden
	 * @param positie
	 * de waarde die getest wordt
	 * @return 
	 * de waarde is true als de x- en y-waarde groter of gelijk zijn dan die van de minimumwaarden en kleiner of gelijk aan de maximumwaarden
	 * |result==positie[0]>=getminpositie()[0] 
			&& positie[1]>=getminpositie()[1]
			&& positie[0]<=getmaxpositie()[0]
			&& positie[1]<=getmaxpositie()[1]
	 */
	public boolean isvalidpositie(long[] positie){
		return positie[0]>=getminpositie()[0] 
				&& positie[1]>=getminpositie()[1]
						&& positie[0]<=getmaxpositie()[0]
								&& positie[1]<=getmaxpositie()[1];
	}
	private final long[] maxpositie;
	/**
	 * geef de maximum positie weer
	 * @note eerste cijfer is de x-coordinaat en tweede is de y-coordinaat
	 * 
	 */
	@Basic
	public long[] getmaxpositie(){
		return maxpositie;
	}
	private final long[] minpositie;
	/**
	 * geef de minimum positie weer
	 * @note eerste cijfer is de x-coordinaat en tweede is de y-coordinaat
	 * 
	 */
	@Basic

	public long[] getminpositie(){
		return minpositie;
	}
	/**
	 * verplaats de robot 1 veld voorwaarts
	 * @throws outofboardexception
	 *  de nieuwe locatie bevindt zich niet op het bord
	 * 			|!isvalidpositie(getpositie()+getrichting())
	 * @post new.getpositie()==getpositie()+getrichting()
	 */
	// eigen outofboardexception ???
	// @basic
	// @outofboardexception serialnumber
	private void moveforward() throws outofboardexception{

		long[]temp={getpositie()[0]+getrichting()[0],getpositie()[1]+getrichting()[1]};
		setpositie(temp);

	}
	/**
	 * verplaats de robot 1 veld voorwaarts en verlaag de energie met de waarde voor de beweging
	 * @throws outofboardexception
	 *  de nieuwe locatie bevindt zich niet op het bord
	 * 			|!isvalidpositie(getpositie(getrichting())
	 * @pre isvalidenergy(getenergy()- getmoveenergy())
	 * @post new.getpositie()==getpositie()+getrichting())+
	 * @post new.getenergy()==getenergy()- getmoveenergy()
	 */
	public void emoveforward() throws outofboardexception{
		moveforward();
		removeenergy(getmoveenergy());
	}
	/**
	 * de robot maakt een linkse kwartdraai en verlaag de energie met de waarde voor de beweging
	 * @pre isvalidenergy(getenergy()- getkwartenergy())
	 * @post if (getrichting()=={0,1}) then new.getrichting()=={-1,0}
	 * @post if (getrichting()=={0,-1}) then new.getrichting()=={1,0}
	 * @post if (getrichting()=={1,0}) then new.getrichting()=={0,1}
	 * @post if (getrichting()=={-1,0}) then new.getrichting()=={0,-1}
	 * @post new.getenergy()==getenergy()- getkwartenergy()
	 */
	public void ekwartlinks(){
		kwartdraailinks();
		removeenergy(getkwartenergy());
	}
	/**
	 * de robot maakt een rechtse kwartdraai en verlaag de energie met de waarde voor de beweging
	 * @pre isvalidenergy(getenergy()- getkwartenergy())
	 * @post if (getrichting()=={0,1}) then new.getrichting()=={1,0}
	 * @post if (getrichting()=={0,-1}) then new.getrichting()=={-1,0}
	 * @post if (getrichting()=={1,0}) then new.getrichting()=={0,-1}
	 * @post if (getrichting()=={-1,0}) then new.getrichting()=={0,1}
	 * @post new.getenergy()==getenergy()- getkwartenergy()
	 */
	public void ekwartrechts(){
		kwartdraairechts();
		removeenergy(getkwartenergy());
	}
	/**
	 * geeft de manhattanafstand tussen 2 punten
	 * @param begin
	 * punt 1
	 * @param eind
	 * punt 2
	 * @return Math.abs(begin[0]-eind[0])+Math.abs(begin[1]-eind[1])
	 * @throws overloadexception
	 * als je een overflow hebt
	 * |!isvalidmanh( begin, eind)
	 */
	public static long  manhattan(long[] begin,long[] eind) throws overloadexception{
		if(!isvalidmanh( begin, eind)){
			throw new overloadexception();
		}
		return Math.abs(begin[0]-eind[0])+Math.abs(begin[1]-eind[1]);
	}
	/**
	 * test of je de manhattanafstand kan berekenen
	 * @param begin
	 * punt 1
	 * @param eind
	 * punt 2
	 * @return
	 * !(begin[0]-eind[0] <0 && begin[0]>eind[0]) 
	 * ||(begin[1]-eind[1]<0 && begin[1]>eind[1])
	 * ||(begin[0]-eind[0] >0 && begin[0]<eind[0]) 
	 * ||(begin[1]-eind[1]>0 && begin[1]<eind[1])
	 */
	public static boolean isvalidmanh(long[] begin,long[] eind){
		return !((begin[0]-eind[0] <0 && begin[0]>eind[0])  ||(begin[1]-eind[1]<0 && begin[1]>eind[1])||(begin[0]-eind[0] >0 && begin[0]<eind[0])  ||(begin[1]-eind[1]>0 && begin[1]<eind[1]));
	}
	/**
	 * kijk of de robot in een juiste richting staat
	 * @param richting
	 * richting
	 * @param eind
	 * doel
	 * @return(manhattan(getposite()+richting ,eind)-manhattan(getpositie(),eind)
			<0)
	 * @throws overloadexception
	 * !isvalidmanh( getpositie(), eind)
	 */
	private boolean isjuisterichting(long[] richting, long[] eind)throws overloadexception{
		long[] temp={getpositie()[0]+richting[0],getpositie()[1]+richting[1]};
		return(manhattan(temp,eind)-manhattan(getpositie(),eind)
				<0);
	}
	/**
	 * bereken de minimale enrgie om naar een positie te gaan
	 * @param eind
	 * @variable aantaldraaien
	 * het aantal keer dat je moet draaien
	 * plaats waar je de enrgie voor wilt berekenen
	 * @return het aantal stappen vermenigvuldigt met de energie per stap plus 
	 * de hoeveelheid energie voor een kwartdraai maal het aantal keer dat je moet draaien
	 * (manhattan(getpositie(),eind)*getmoveenergy())+(aantaldraaien*getkwartenergy())
	 * @throws overloadexception
	 * !isvalidmanh( getpositie(), eind)
	 */
	/*
	 * @variable aantaldraaien
	 * het aantal keer dat je moet draaien
	 * 
	 * kan de robot wachten???
	 */
	public long zoekenergievoorpositie(long[] eind) throws overloadexception{
		if(eind[0]== getpositie()[0]&& eind[1]== getpositie()[1])return 0;
		long aantaldraaien =0;
		if(isjuisterichting(getrichting(),eind)){
			long[] temp={getrichting()[1],getrichting()[0]};
			if(isjuisterichting(temp,eind)){
				aantaldraaien =1;
			}
			long[] temp1={-getrichting()[1],-getrichting()[0]};
			if(isjuisterichting(temp1,eind)){
				aantaldraaien =1;
			}
		}
		else{
			long[] temp={-getrichting()[0],-getrichting()[1]};
			if(isjuisterichting(temp,eind)){
				aantaldraaien =2;
			}
			else{				
				aantaldraaien =1;
			}
		}
		return (manhattan(getpositie(),eind)*getmoveenergy())+(aantaldraaien*getkwartenergy());
	}
	public static void tweerobotsbijelkaar(IRobot robot1,IRobot robot2) throws overloadexception,outofboardexception{
		Long x1 = Math.min(robot1.getpositie()[0],robot2.getpositie()[0]);
		Long x2 = Math.max(robot1.getpositie()[0],robot2.getpositie()[0]);
		Long y1 = Math.min(robot1.getpositie()[1],robot2.getpositie()[1]);
		Long y2 = Math.max(robot1.getpositie()[1],robot2.getpositie()[1]);
		long[] optimaal={robot1.getpositie()[0],robot1.getpositie()[1],robot2.getpositie()[0],robot2.getpositie()[1]};
		for(long i= x1;i<= x2;i++){
			for(long j= y1;j<= y2;j++){
				long[] temp ={i,j};
				long energie1 = robot1.zoekenergievoorpositie(temp);
				if (energie1<=robot1.getenergy()){
					for(long g = x1;g<=x2;g++){
						for(long v=y1; v<=y2;v++){
							long[] temp2 ={g,v};
							long energie2 = robot2.zoekenergievoorpositie(temp2);
							if(energie2<= robot2.getenergy()&& !(temp[0]==temp2[0]&& temp[1]==temp2[1])){
								optimaal = min(optimaal,robot1,temp,robot2,temp2);
							}
						}
					}
				}
			}
		}
		long[] temp3= {optimaal[0],optimaal[1]};
		robot1.movenaar(temp3);
		long[] temp4= {optimaal[2],optimaal[3]};
		robot2.movenaar(temp4);
	}
	private static long[] min(long[] optimaal, IRobot robot1, long[] positie1, IRobot robot2,long[] positie2 ) throws overloadexception{
		long [] optimaal1 = {optimaal[0],optimaal[1]};
		long [] optimaal2 = {optimaal[2],optimaal[3]};
		if(manhattan(optimaal1,optimaal2)>manhattan(positie1,positie2)){
			long[] ans= {positie1[0],positie1[1],positie2[0],positie2[1]};
			return ans;
		}
		if(manhattan(optimaal1,optimaal2)<manhattan(positie1,positie2)){
			return optimaal;
		}
		if((robot1.zoekenergievoorpositie(optimaal1)+robot2.zoekenergievoorpositie(optimaal2))>
		(robot1.zoekenergievoorpositie(positie1)+robot2.zoekenergievoorpositie(positie2))){
			long[] ans= {positie1[0],positie1[1],positie2[0],positie2[1]};
			return ans;
		}
		if((robot1.zoekenergievoorpositie(optimaal1)+robot2.zoekenergievoorpositie(optimaal2))<
				(robot1.zoekenergievoorpositie(positie1)+robot2.zoekenergievoorpositie(positie2))){
			return optimaal;
		}
		return optimaal;	
	}
	private  void movenaar(long[] eind) throws overloadexception,outofboardexception{
		while(!(getpositie()[0]==eind[0] && getpositie()[1]==eind[1])){
			if(isjuisterichting(getrichting(),eind)){
				emoveforward();
			}
			else{
				long[] temp={-getrichting()[1],getrichting()[0]};
				if(isjuisterichting(temp,eind)){
					ekwartlinks();
				}
				else{			
					ekwartrechts();
				}
			}
		}
	}
}
/* ander idee public static Robot[] tweerobosbijelkaar(Robot robot1,Robot robot2){
		if((robot1.getenergy()<robot1.getmoveenergy() && robot2.getenergy()<robot2.getmoveenergy())||manhattan(robot1.getpositie(),robot2.getpositie())==1){
			Robot[] returner ={robot1,robot2};
			return returner;
		}
		else{
			Robot robo11 = copy(robot1);
			robo11.ekwartrechts();
			Robot robo12 = copy(robot2);
			Robot robo21 = copy(robot1);
			robo21.ekwartlinks();
			Robot robo22 = copy(robot2);
			robot1.emoveforward();
			return max(tweerobosbijelkaar(robot2,robot1),tweerobosbijelkaar(robo12,robo11),tweerobosbijelkaar(robo22,robo21));
		}
	}
	public static Robot copy(Robot robot){
		Robot Robottemp = new Robot(robot.getenergy(),robot.getpositie(),robot.getrichting());
		return Robottemp;
	}
	public static Robot[] max(Robot[] robots, Robot[] robots2, Robot[] robots3){
		return max(max(robots,robots2),robots3);
	}
	public static Robot[] max(Robot[] robots, Robot[] robots2){
		if( manhattan(robots[0].getpositie(),robots[1].getpositie())< manhattan(robots2[0].getpositie(),robots2[1].getpositie())){
			return robots;
		}
		if( manhattan(robots[0].getpositie(),robots[1].getpositie())> manhattan(robots2[0].getpositie(),robots2[1].getpositie())){
			return robots2;
		}
		if((robots[0].getenergy()+robots[1].getenergy())<(robots2[0].getenergy()+robots2[1].getenergy())){
			return robots2;

	}
		return robots;
}
}
 */